package main

import (
	"fmt"
	"log"

	"gobatis/core/config"
	"gobatis/errors"
)

// ErrorHandlingDemo demonstrates the unified error handling system
func ErrorHandlingDemo() {
	fmt.Println("=== GoBatis Unified Error Handling System Demo ===")

	// 1. Configuration error demo
	fmt.Println("1. Configuration Error Demo:")
	config := config.NewConfiguration()
	err := config.SetDataSource("invalid_driver", "invalid_datasource")
	if err != nil {
		if errors.IsErrorCode(err, errors.DatabaseConnectionError) {
			fmt.Printf("   Database connection error detected: %v\n", err)
			if gobatisErr, ok := err.(*errors.GoBatisError); ok {
				if driver, exists := gobatisErr.GetContext("driverName"); exists {
					fmt.Printf("   Invalid driver name: %v\n", driver)
				}
			}
		}
	}

	// 2. Parameter binding error demo
	fmt.Println("\n2. Parameter Binding Error Demo:")
	paramBindingErr := errors.NewParameterBindingError("unable to bind parameters", fmt.Errorf("original error"))
	paramBindingErr.WithContext("sql", "SELECT * FROM users WHERE id = #{id}")
	paramBindingErr.WithContext("parameter", "invalid_parameter")
	fmt.Printf("   Parameter binding error: %v\n", paramBindingErr)

	// 3. Result mapping error demo
	fmt.Println("\n3. Result Mapping Error Demo:")
	mappingErr := errors.NewResultMappingError("unable to map result to target type", fmt.Errorf("type incompatible"))
	mappingErr.WithContext("targetType", "User")
	mappingErr.WithContext("sourceType", "map[string]interface{}")
	fmt.Printf("   Result mapping error: %v\n", mappingErr)

	// 4. XML parsing error demo
	fmt.Println("\n4. XML Parsing Error Demo:")
	xmlErr := errors.NewXMLParseError("XML parsing failed", fmt.Errorf("invalid XML format"))
	xmlErr.WithContext("xmlPath", "/path/to/mapper.xml")
	xmlErr.WithContext("line", 25)
	fmt.Printf("   XML parsing error: %v\n", xmlErr)

	// 5. Statement not found error demo
	fmt.Println("\n5. Statement Not Found Error Demo:")
	stmtErr := errors.NewStatementError("UserMapper.getNonExistentUser")
	fmt.Printf("   Statement not found error: %v\n", stmtErr)

	// 6. Error chain demo
	fmt.Println("\n6. Error Chain Demo:")
	originalErr := fmt.Errorf("database connection timeout")
	wrappedErr := errors.Wrap(errors.DatabaseQueryError, "query execution failed", originalErr)
	doubleWrappedErr := errors.Wrap(errors.StatementNotFound, "statement execution error", wrappedErr)

	fmt.Printf("   Final error: %v\n", doubleWrappedErr)
	// Using standard library errors.Unwrap
	stdErr := error(doubleWrappedErr)
	if wrappedOnce := stdErr.(*errors.GoBatisError).Unwrap(); wrappedOnce != nil {
		if wrappedTwice := wrappedOnce.(*errors.GoBatisError).Unwrap(); wrappedTwice != nil {
			fmt.Printf("   Original error: %v\n", wrappedTwice)
		}
	}

	// 7. Error type checking demo
	fmt.Println("\n7. Error Type Checking Demo:")
	testErr := errors.NewDatabaseError("connection failed", fmt.Errorf("network error"))

	if errors.IsErrorCode(testErr, errors.DatabaseConnectionError) {
		fmt.Printf("   Confirmed this is a database connection error: %v\n", testErr)
	}

	errorCode := errors.GetErrorCode(testErr)
	fmt.Printf("   Error code: %v (%s)\n", errorCode, errorCode.String())

	fmt.Println("\n=== Demo Complete ===")
}

func main() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)
	ErrorHandlingDemo()
}
